﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using PloobsEngine.Material;
using PloobsEngine.Light;
using PloobsEngine.Cameras;
using PloobsEngine.Modelo;

namespace PloobsEngine.SceneControl
{
    public enum ShadowFilter
    {
        NONE, PCF2x2, PCF3x3, PCF2x2Variance, PCF3x3BLUR, PCF5x5BLUR
    }

    public class ShadowLightMap : IDeferredLightMap
    {        
        private QuadRender quadRenderer;
        private EngineStuff engine;
        private RenderTarget2D lightRT;
        private RenderTarget2D shadowRT;
        private RenderTarget2D deferredRT;
        private Effect directionalLightEffect;
        private Effect pointLightEffect;
        private Effect spotLightEffect;
        private Effect Depth;
        private Model sphereModel;
        private Model coneModel;        
        private Texture2D shadowMap;                
        private Texture2D content;        
        private ShadowFilter shadowFilterDirection = ShadowFilter.NONE;
        private ShadowFilter shadowFilterSpot = ShadowFilter.NONE;
        BlurMode lightRtBlurMode = BlurMode.NONE;
        GBlurCPUPostEffect blur;
        RenderHelper rh;
        RenderTarget2D rt;
        

        public BlurMode ShadowBlurMode
        {
            get { return lightRtBlurMode; }
            set { lightRtBlurMode = value; }
        }

        public ShadowFilter DirectionalShadowFilter
        {
            get { return shadowFilterDirection; }
            set { shadowFilterDirection = value; }
        }

        public ShadowFilter SpotShadowFilter
        {
            get { return shadowFilterSpot; }
            set { shadowFilterSpot = value; }
        }
        

        private DepthStencilBuffer depthStencil;
        private int shadownBufferSize = EngineStuff.BackBufferWidth;
        
        public int ShadownBufferSize
        {
            get { return shadownBufferSize; }
            set { shadownBufferSize = value; }
        }

        #region IDeferredLightMap Members

        private void DrawDirectionalLight(ICamera camera, DirectionalLight dl, IDeferredGBuffer DeferredGBuffer)
        {
            directionalLightEffect.Parameters["BIAS"].SetValue(dl.SHADOWBIAS);
            directionalLightEffect.Parameters["shadowBufferSize"].SetValue(shadownBufferSize);
            directionalLightEffect.Parameters["xShadowMap"].SetValue(shadowMap);
            directionalLightEffect.Parameters["colorMap"].SetValue(DeferredGBuffer[GBufferTypes.COLOR]);
            directionalLightEffect.Parameters["normalMap"].SetValue(DeferredGBuffer[GBufferTypes.NORMAL]);
            directionalLightEffect.Parameters["depthMap"].SetValue(DeferredGBuffer[GBufferTypes.DEPH]);
            directionalLightEffect.Parameters["xLightViewProjection"].SetValue(dl.ViewMatrix * dl.ProjMatrix ); 
            directionalLightEffect.Parameters["View"].SetValue(camera.View);
            directionalLightEffect.Parameters["Projection"].SetValue(camera.Projection);
            directionalLightEffect.Parameters["cameraPosition"].SetValue(camera.Position);
            directionalLightEffect.Parameters["shadown"].SetValue(dl.CastShadown);
            directionalLightEffect.Parameters["InvertViewProjection"].SetValue(Matrix.Invert(camera.View * camera.Projection));
            directionalLightEffect.Parameters["halfPixel"].SetValue(EngineStuff.HalfPixel);
            directionalLightEffect.Parameters["lightDirection"].SetValue(dl.LightDirection);
            directionalLightEffect.Parameters["Color"].SetValue(dl.Color.ToVector3());
            directionalLightEffect.Parameters["lightIntensity"].SetValue(dl.LightIntensity);
            directionalLightEffect.Begin();
            directionalLightEffect.Techniques[0].Passes[0].Begin();
            EngineStuff.GraphicsDevice.RenderState.DepthBufferEnable = false;
            quadRenderer.Render(Vector2.One * -1, Vector2.One);
            EngineStuff.GraphicsDevice.RenderState.DepthBufferEnable = true;
            directionalLightEffect.Techniques[0].Passes[0].End();
            directionalLightEffect.End();   

            //directionalLightEffect.Parameters["colorMap"].SetValue(DeferredGBuffer[GBufferTypes.COLOR]);
            //directionalLightEffect.Parameters["normalMap"].SetValue(DeferredGBuffer[GBufferTypes.NORMAL]);
            //directionalLightEffect.Parameters["depthMap"].SetValue(DeferredGBuffer[GBufferTypes.DEPH]);
            //directionalLightEffect.Parameters["cameraPosition"].SetValue(camera.Position);
            //directionalLightEffect.Parameters["InvertViewProjection"].SetValue(Matrix.Invert(camera.View * camera.Projection));
            //directionalLightEffect.Parameters["halfPixel"].SetValue(EngineStuff.HalfPixel);            
            //directionalLightEffect.Parameters["lightDirection"].SetValue(dl.LightDirection);
            //directionalLightEffect.Parameters["Color"].SetValue(dl.Color.ToVector3());
            //directionalLightEffect.Parameters["lightIntensity"].SetValue(dl.LightIntensity);

            //directionalLightEffect.Begin();
            //directionalLightEffect.Techniques[0].Passes[0].Begin();
            //quadRenderer.Render(Vector2.One * -1, Vector2.One);
            //directionalLightEffect.Techniques[0].Passes[0].End();
            //directionalLightEffect.End();

           }

        private void DrawPointLight(ICamera camera, PointLight pl, IDeferredGBuffer DeferredGBuffer)
        {

            EngineStuff.GraphicsDevice.RenderState.DepthBufferEnable = false;
            pointLightEffect.Parameters["colorMap"].SetValue(DeferredGBuffer[GBufferTypes.COLOR]);
            pointLightEffect.Parameters["normalMap"].SetValue(DeferredGBuffer[GBufferTypes.NORMAL]);
            pointLightEffect.Parameters["depthMap"].SetValue(DeferredGBuffer[GBufferTypes.DEPH]);
            pointLightEffect.Parameters["Projection"].SetValue(camera.Projection);
            pointLightEffect.Parameters["View"].SetValue(camera.View);
            pointLightEffect.Parameters["cameraPosition"].SetValue(camera.Position);
            pointLightEffect.Parameters["InvertViewProjection"].SetValue(Matrix.Invert(camera.View * camera.Projection));
            pointLightEffect.Parameters["halfPixel"].SetValue(EngineStuff.HalfPixel);
            Matrix sphereWorldMatrix = Matrix.CreateScale(pl.LightRadius) * Matrix.CreateTranslation(pl.LightPosition);
            pointLightEffect.Parameters["World"].SetValue(sphereWorldMatrix);
            pointLightEffect.Parameters["lightPosition"].SetValue(pl.LightPosition);
            pointLightEffect.Parameters["Color"].SetValue(pl.Color.ToVector3());
            pointLightEffect.Parameters["lightRadius"].SetValue(pl.LightRadius);
            pointLightEffect.Parameters["lightIntensity"].SetValue(pl.LightIntensity);
            pointLightEffect.Parameters["quadratic"].SetValue(pl.UsePointLightQuadraticAttenuation);

            float cameraToCenter = Vector3.Distance(camera.Position, pl.LightPosition);

            if (cameraToCenter < pl.LightRadius)
                EngineStuff.GraphicsDevice.RenderState.CullMode = CullMode.CullClockwiseFace;
            else
                EngineStuff.GraphicsDevice.RenderState.CullMode = CullMode.CullCounterClockwiseFace;

            pointLightEffect.Begin();
            pointLightEffect.Techniques[0].Passes[0].Begin();

            //EngineStuff.GraphicsDevice.VertexDeclaration = fsVertexDeclaration;
            //EngineStuff.GraphicsDevice.DrawUserPrimitives<VertexPositionTexture>(PrimitiveType.TriangleStrip, fsVertices, 0, 2);

            foreach (ModelMesh mesh in sphereModel.Meshes)
            {
                foreach (ModelMeshPart meshPart in mesh.MeshParts)
                {
                    EngineStuff.GraphicsDevice.VertexDeclaration = meshPart.VertexDeclaration;
                    EngineStuff.GraphicsDevice.Vertices[0].SetSource(mesh.VertexBuffer, meshPart.StreamOffset, meshPart.VertexStride);
                    EngineStuff.GraphicsDevice.Indices = mesh.IndexBuffer;
                    EngineStuff.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, meshPart.BaseVertex, 0, meshPart.NumVertices, meshPart.StartIndex, meshPart.PrimitiveCount);
                }
            }                 
                 pointLightEffect.Techniques[0].Passes[0].End();
                 pointLightEffect.End();
                 EngineStuff.GraphicsDevice.RenderState.CullMode = CullMode.CullCounterClockwiseFace;
                 EngineStuff.GraphicsDevice.RenderState.DepthBufferEnable = false;

            }

        private void BlurDistances(ref Texture2D toBlur)
        {                        
            if (lightRtBlurMode == BlurMode.SINGLE || lightRtBlurMode == BlurMode.DOUBLE)
            {
                EngineStuff.GraphicsDevice.SetRenderTarget(0, deferredRT);
                EngineStuff.GraphicsDevice.RenderState.AlphaBlendEnable = false;
                EngineStuff.GraphicsDevice.RenderState.DepthBufferEnable = false;
                EngineStuff.GraphicsDevice.RenderState.DepthBufferWriteEnable = false;
                blur.ImageToBlur = toBlur;
                
                blur.Draw(rh, EngineStuff.GetCurrentGameTime(), new Rectangle(), null);

                if (lightRtBlurMode == BlurMode.DOUBLE)
                {
                    EngineStuff.GraphicsDevice.SetRenderTarget(0, null);
                    toBlur = deferredRT.GetTexture();
                    EngineStuff.GraphicsDevice.SetRenderTarget(0, deferredRT);
                    blur.ImageToBlur = toBlur;
                    blur.Draw(rh, EngineStuff.GetCurrentGameTime(), new Rectangle(), null);
                }
            }


        }

        private void DrawnSpotLight(ICamera camera, SpotLight sl, IDeferredGBuffer DeferredGBuffer)
        {
                    spotLightEffect.Parameters["shadowBufferSize"].SetValue(shadownBufferSize);
                    spotLightEffect.Parameters["BIAS"].SetValue(sl.SHADOWBIAS);
                    spotLightEffect.Parameters["xShadowMap"].SetValue(shadowMap);
                    spotLightEffect.Parameters["colorMap"].SetValue(DeferredGBuffer[GBufferTypes.COLOR]);
                    spotLightEffect.Parameters["normalMap"].SetValue(DeferredGBuffer[GBufferTypes.NORMAL]);
                    spotLightEffect.Parameters["depthMap"].SetValue(DeferredGBuffer[GBufferTypes.DEPH]);            
                    spotLightEffect.Parameters["xLightViewProjection"].SetValue(sl.ViewMatrix * sl.ProjMatrix);
                    spotLightEffect.Parameters["View"].SetValue(camera.View);
                    spotLightEffect.Parameters["Projection"].SetValue(camera.Projection);
                    spotLightEffect.Parameters["cameraPosition"].SetValue(camera.Position);
                    spotLightEffect.Parameters["shadown"].SetValue(sl.CastShadown);


                    spotLightEffect.Parameters["InvertViewProjection"].SetValue(Matrix.Invert(camera.View * camera.Projection));
                    spotLightEffect.Parameters["halfPixel"].SetValue(EngineStuff.HalfPixel);
                    spotLightEffect.Parameters["lightPosition"].SetValue(sl.Position);

                    spotLightEffect.Parameters["lightDirection"].SetValue(sl.Direction);
                    spotLightEffect.Parameters["lightRadius"].SetValue(sl.LightRadius);
                    spotLightEffect.Parameters["lightDecayExponent"].SetValue(sl.ConeDecay);
                    spotLightEffect.Parameters["Color"].SetValue(sl.Color.ToVector3());
                    spotLightEffect.Parameters["lightAngleCosine"].SetValue(sl.LightAngleCosine);
                    spotLightEffect.Parameters["lightIntensity"].SetValue(sl.LightIntensity);

                    //double angle = Math.Pow(sl.LightAngleCosine, 2);
                    //double lateralScale = sl.LightRadius * (Math.Sqrt((1 / angle) - 1));
                    //Matrix sphereWorldMatrix = Matrix.CreateScale((float)lateralScale, sl.LightRadius, (float)lateralScale) * Matrix.CreateWorld(sl.Position, sl.Direction, Vector3.Up);
                    //spotLightEffect.Parameters["World"].SetValue(sphereWorldMatrix);
        
                    spotLightEffect.Begin();                    
                    spotLightEffect.Techniques[0].Passes[0].Begin();
                    
                    EngineStuff.GraphicsDevice.RenderState.DepthBufferEnable = false;
                    
                    quadRenderer.Render(Vector2.One * -1, Vector2.One);

                 
                    EngineStuff.GraphicsDevice.RenderState.DepthBufferEnable = true;

                    //foreach (ModelMesh mesh in coneModel.Meshes)
                    //{
                    //    foreach (ModelMeshPart meshPart in mesh.MeshParts)
                    //    {
                    //        EngineStuff.GraphicsDevice.VertexDeclaration = meshPart.VertexDeclaration;
                    //        EngineStuff.GraphicsDevice.Vertices[0].SetSource(mesh.VertexBuffer, meshPart.StreamOffset, meshPart.VertexStride);
                    //        EngineStuff.GraphicsDevice.Indices = mesh.IndexBuffer;
                    //        EngineStuff.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, meshPart.BaseVertex, 0, meshPart.NumVertices, meshPart.StartIndex, meshPart.PrimitiveCount);
                    //    }
                    //}

                    spotLightEffect.Techniques[0].Passes[0].End();
                    spotLightEffect.End();
                    
                }
        

        public void DrawScene(GameTime gameTime, IWorld world,Matrix view, Matrix proj )
        {                        
            
            foreach (IObject item in world.Objects)
            {
                if(item.Material.MaterialType == MaterialType.DEFERRED)
                {
                if(item.Material.AffectedByShadow == true && item.Modelo != null)
                {
                    if (item.Material.Shadder.DepthExtractor != null)
                    {
                        item.Material.Shadder.DepthExtractor.ExtractDepthFromObject(item, view, proj);                     
                    }
                    else
                    {
                        IModelo modelo = item.Modelo;
                        Matrix[] boneTransforms = modelo.getBonesTransformation();
                        Matrix wld = item.getWorldMatrix();

                        for (int i = 0; i < modelo.MeshNumber; i++)
                        {                                   
                            BatchInformation[] bi = modelo.GetBatchInformation(i);
                            Matrix w1 = Matrix.Multiply(wld, boneTransforms[modelo.GetParentBoneIndex(i)]);
                            
                            for (int j = 0; j < bi.Count(); j++)
                            {
                                EngineStuff.GraphicsDevice.VertexDeclaration = bi[j].VertexDeclaration;
                                EngineStuff.GraphicsDevice.Vertices[0].SetSource(modelo.GetVertexBuffer(i), bi[j].StreamOffset, bi[j].VertexStride);
                                EngineStuff.GraphicsDevice.Indices = modelo.GetIndexBuffer(i);                                                
                        
                                Depth.Parameters["xWorld"].SetValue(w1);
                                Depth.CurrentTechnique = Depth.Techniques["ShadowMap"];
                                Depth.Parameters["xView"].SetValue(view);
                                Depth.Parameters["xProjection"].SetValue(proj);

                                Depth.Begin();                                
                                Depth.CurrentTechnique.Passes[0].Begin();
                                EngineStuff.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, bi[j].BaseVertex, 0, bi[j].NumVertices, bi[j].StartIndex, bi[j].PrimitiveCount);                       
                                Depth.CurrentTechnique.Passes[0].End();
                                Depth.End();

                            }
                        }
                    }
                }
                }
            }
        }
       
        private void RenderShadowMap(Matrix view, Matrix proj, IWorld world, IDeferredGBuffer deferredGBuffer)
        {            
            EngineStuff.GraphicsDevice.SetRenderTarget(0, shadowRT); 
            DepthStencilBuffer ds = EngineStuff.GraphicsDevice.DepthStencilBuffer  ;
            EngineStuff.GraphicsDevice.DepthStencilBuffer = depthStencil;
            EngineStuff.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer,new Color(1, 1, 1, 1),1,0);
            EngineStuff.GraphicsDevice.RenderState.DepthBufferEnable = true;
            EngineStuff.GraphicsDevice.RenderState.AlphaBlendEnable = false;
            EngineStuff.GraphicsDevice.RenderState.DepthBufferWriteEnable = true;                                
            DrawScene(EngineStuff.GetCurrentGameTime(), world,view,proj);
            EngineStuff.GraphicsDevice.SetRenderTarget(0, null);
            EngineStuff.GraphicsDevice.RenderState.DepthBufferEnable = false;
            EngineStuff.GraphicsDevice.RenderState.AlphaBlendEnable = true;            
            shadowMap = shadowRT.GetTexture();
            EngineStuff.GraphicsDevice.DepthStencilBuffer = ds;            
            EngineStuff.GraphicsDevice.SetRenderTarget(0, lightRT);
        }

        public void DrawLights(GameTime gameTime, IWorld world, IDeferredGBuffer deferredGBuffer)
        {
            EngineStuff.GraphicsDevice.Clear(ClearOptions.DepthBuffer | ClearOptions.Target, Color.TransparentBlack, 1, 0);            
            EngineStuff.GraphicsDevice.Clear(Color.TransparentBlack);
            EngineStuff.GraphicsDevice.RenderState.AlphaBlendEnable = true;
            EngineStuff.GraphicsDevice.RenderState.AlphaBlendOperation = BlendFunction.Add;
            EngineStuff.GraphicsDevice.RenderState.SourceBlend = Blend.One;
            EngineStuff.GraphicsDevice.RenderState.DestinationBlend = Blend.One;
            EngineStuff.GraphicsDevice.RenderState.SeparateAlphaBlendEnabled = false;
            EngineStuff.GraphicsDevice.RenderState.DepthBufferEnable = false;            

            foreach (ILight light in world.Lights.Where( (a) => a.CastShadown == true))
            {
                    switch (light.LightType)
                    {

                        case LightType.Deferred_Directional:
                            DirectionalLight dl = light as DirectionalLight;
                            if (shadowFilterDirection == ShadowFilter.PCF3x3BLUR || shadowFilterDirection == ShadowFilter.PCF5x5BLUR)
                            {
                                dl.FakeViewProjection(world.ActiveCamera);
                                RenderShadowMap(dl.ViewMatrix, dl.ProjMatrix, world, deferredGBuffer);
                                EngineStuff.GraphicsDevice.RenderState.DepthBufferEnable = false;
                                EngineStuff.GraphicsDevice.RenderState.AlphaBlendEnable = false;            
                                ///lightrt --shadowmap correto
                                EngineStuff.GraphicsDevice.SetRenderTarget(0, deferredRT );
                                DepthStencilBuffer ds = EngineStuff.GraphicsDevice.DepthStencilBuffer;
                                EngineStuff.GraphicsDevice.DepthStencilBuffer = depthStencil;
                                if (shadowFilterDirection == ShadowFilter.PCF5x5BLUR)
                                {
                                    directionalLightEffect.CurrentTechnique = directionalLightEffect.Techniques["DEFERREDPCF4x4"];
                                }
                                else
                                {
                                    directionalLightEffect.CurrentTechnique = directionalLightEffect.Techniques["DEFERREDPCF3x3"];
                                }
                                DrawDirectionalLight(world.ActiveCamera, dl, deferredGBuffer);                                
                                EngineStuff.GraphicsDevice.SetRenderTarget(0, null);
                                Texture2D ToBlur = deferredRT.GetTexture();                                
                                BlurDistances(ref ToBlur);
                                EngineStuff.GraphicsDevice.SetRenderTarget(0, null);
                                shadowMap = deferredRT.GetTexture();                                
                                EngineStuff.GraphicsDevice.SetRenderTarget(0, lightRT);
                                directionalLightEffect.CurrentTechnique = directionalLightEffect.Techniques["DEFERREDPCF3x3AFTER"];
                                EngineStuff.GraphicsDevice.RenderState.DepthBufferEnable = false;
                                EngineStuff.GraphicsDevice.RenderState.AlphaBlendEnable = true;            
                                DrawDirectionalLight(world.ActiveCamera, dl, deferredGBuffer);
                                directionalLightEffect.CurrentTechnique = directionalLightEffect.Techniques["NORMAL"];
                                EngineStuff.GraphicsDevice.DepthStencilBuffer = ds;                                

                            }
                            else
                            {
                                dl.FakeViewProjection(world.ActiveCamera);
                                RenderShadowMap(dl.ViewMatrix, dl.ProjMatrix, world, deferredGBuffer);
                                DeferredDebugImageRender dir = new DeferredDebugImageRender(new Rectangle(0,0,250,250), shadowMap);
                                DeferredRenderTechnic.DebugImages.Add(dir);
                                DrawDirectionalLight(world.ActiveCamera, dl, deferredGBuffer);
                                
                            }                           

                            

                            break;
                        case LightType.Deferred_Point:
                            EngineStuff.GraphicsDevice.SetRenderTarget(0, lightRT);
                            DrawPointLight(world.ActiveCamera, light as PointLight, deferredGBuffer);
                            break;
                        case LightType.Deferred_Spot:
                            SpotLight sl = light as SpotLight;
                            if(sl.CastShadown)
                                RenderShadowMap(sl.ViewMatrix,sl.ProjMatrix, world, deferredGBuffer);                            
                            DrawnSpotLight(world.ActiveCamera, sl, deferredGBuffer);
                            break;
                        default:
                            throw new Exception("Light type Unexpected");
                    }                
                }

            //if (lightRtBlurMode == BlurMode.SINGLE || lightRtBlurMode == BlurMode.DOUBLE)
            //{
            //    EngineStuff.GraphicsDevice.SetRenderTarget(0, lightRT);
            //    EngineStuff.GraphicsDevice.RenderState.AlphaBlendEnable = false;
            //    EngineStuff.GraphicsDevice.RenderState.DepthBufferEnable = false;
            //    EngineStuff.GraphicsDevice.RenderState.DepthBufferWriteEnable = false;
            //    blur.ImageToBlur = content;
            //    blur.Draw(rh, EngineStuff.GetCurrentGameTime(), new Rectangle(), null);

            //    if (lightRtBlurMode == BlurMode.DOUBLE)
            //    {
            //        EngineStuff.GraphicsDevice.SetRenderTarget(0, null);
            //        content = lightRT.GetTexture();
            //        EngineStuff.GraphicsDevice.SetRenderTarget(0, lightRT);
            //        blur.ImageToBlur = content;
            //        blur.Draw(rh, EngineStuff.GetCurrentGameTime(), new Rectangle(), null);                 
            //    }                
            //}

            EngineStuff.GraphicsDevice.RenderState.AlphaBlendEnable = true;
            EngineStuff.GraphicsDevice.RenderState.SeparateAlphaBlendEnabled = false;
            EngineStuff.GraphicsDevice.RenderState.DepthBufferEnable = false;            

            foreach (ILight light in world.Lights.Where((a) => a.CastShadown != true))
            {
                switch (light.LightType)
                {

                    case LightType.Deferred_Directional:
                        DirectionalLight dl = light as DirectionalLight;
                        EngineStuff.GraphicsDevice.SetRenderTarget(0, lightRT);
                        DrawDirectionalLight(world.ActiveCamera, dl, deferredGBuffer);
                        break;
                    case LightType.Deferred_Point:
                        EngineStuff.GraphicsDevice.SetRenderTarget(0, lightRT);
                        DrawPointLight(world.ActiveCamera, light as PointLight, deferredGBuffer);
                        break;
                    case LightType.Deferred_Spot:
                        SpotLight sl = light as SpotLight;
                        EngineStuff.GraphicsDevice.SetRenderTarget(0, lightRT);
                        DrawnSpotLight(world.ActiveCamera, sl, deferredGBuffer);
                        break;
                    default:
                        throw new Exception("Light type Unexpected");
                }
            }

            EngineStuff.GraphicsDevice.SetRenderTarget(0, null);
            content = lightRT.GetTexture();

            DeferredDebugImageRender dir2 = new DeferredDebugImageRender(new Rectangle(250, 0, 250, 250), content);
            DeferredRenderTechnic.DebugImages.Add(dir2);


        }
        
        public void LoadContent(EngineStuff engine, bool useFloatBuffer)
        {
            this.engine = engine;        
            quadRenderer = new QuadRender(EngineStuff.GraphicsDevice);            
            
            //shadowRT = new RenderTarget2D(EngineStuff.GraphicsDevice, shadownBufferSize, shadownBufferSize, 0, SurfaceFormat.HalfSingle);
            shadowRT = new RenderTarget2D(EngineStuff.GraphicsDevice, shadownBufferSize, shadownBufferSize, 0, SurfaceFormat.Single);
            depthStencil = new DepthStencilBuffer(EngineStuff.GraphicsDevice, shadownBufferSize, shadownBufferSize, DepthFormat.Depth24Stencil8);

            if (useFloatBuffer)
                lightRT = EngineStuff.GetDefaultBuffer(SurfaceFormat.HalfVector4);
            else
                lightRT = EngineStuff.GetDefaultColorBuffer();

            Depth = EngineStuff.InternalContentManager.GetAsset<Effect>("ShadowDepth");
            //directionalLightEffect = EngineStuff.InternalContentManager.GetAsset<Effect>("ShadowDirectional");
            pointLightEffect = EngineStuff.InternalContentManager.GetAsset<Effect>("PointLight");            
            //spotLightEffect = EngineStuff.InternalContentManager.GetAsset<Effect>("ShadowSpot");
            //Depth = EngineStuff.CustomContentManager.GetAsset<Effect>("..\\Content\\Effects\\ShadowDepth");
            //directionalLightEffect = EngineStuff.CustomContentManager.GetAsset<Effect>("..\\Content\\Effects\\ShadowDirectional");            
            directionalLightEffect = EngineStuff.InternalContentManager.GetAsset<Effect>("ShadowDirectional");            
            //pointLightEffect = EngineStuff.CustomContentManager.GetAsset<Effect>("..\\Content\\Effects\\PointLight");            
            //spotLightEffect = EngineStuff.CustomContentManager.GetAsset<Effect>("..\\Content\\Effects\\ShadowSpot");
            spotLightEffect = EngineStuff.InternalContentManager.GetAsset<Effect>("ShadowSpot");
            sphereModel = EngineStuff.InternalContentManager.GetAsset<Model>("Dsphere");
            coneModel = EngineStuff.InternalContentManager.GetAsset<Model>("cone");
            blur = new GBlurCPUPostEffect();
            rh = new RenderHelper(engine);
            blur.init(engine);
            rt = EngineStuff.GetDefaultColorBuffer();
            deferredRT = EngineStuff.GetDefaultDepthBuffer(shadownBufferSize,shadownBufferSize);

            switch (shadowFilterDirection)
            {
                case ShadowFilter.NONE:
                    directionalLightEffect.CurrentTechnique = directionalLightEffect.Techniques["NORMAL"];
                    break;
                case ShadowFilter.PCF2x2:
                    directionalLightEffect.CurrentTechnique = directionalLightEffect.Techniques["PCF2x2"];
                    break;
                case ShadowFilter.PCF3x3:
                    directionalLightEffect.CurrentTechnique = directionalLightEffect.Techniques["PCF3x3"];
                    break;
                case ShadowFilter.PCF2x2Variance:
                    directionalLightEffect.CurrentTechnique = directionalLightEffect.Techniques["PCF2x2Variance"];
                    break;
                case ShadowFilter.PCF3x3BLUR:
                    directionalLightEffect.CurrentTechnique = directionalLightEffect.Techniques["NORMAL"];
                    break;                        
                default:
                    break;
            }


            switch (shadowFilterSpot)
            {
                case ShadowFilter.NONE:
                    spotLightEffect.CurrentTechnique = spotLightEffect.Techniques["Technique1"];
                    break;
                case ShadowFilter.PCF2x2:
                    spotLightEffect.CurrentTechnique = spotLightEffect.Techniques["Technique1"];
                    break;
                case ShadowFilter.PCF3x3:
                    spotLightEffect.CurrentTechnique = spotLightEffect.Techniques["Technique2"];
                    break;
                case ShadowFilter.PCF2x2Variance:
                    spotLightEffect.CurrentTechnique = spotLightEffect.Techniques["Technique1"];
                    break;
                default:
                    break;
            }

        }

        #endregion

        #region IDeferredLightMap Members


        public Texture2D this[DeferredLightMapType type]
        {
            get
            {
                switch (type)
                {
                    case DeferredLightMapType.LIGHTMAP:
                        return content;
                    default:
                        throw new Exception("Type not present in this implementation");
                }

            }
        }

        #endregion

        #region IDeferredLightMap Members

        public void SetLightMap()
        {
            EngineStuff.GraphicsDevice.SetRenderTarget(0, lightRT);
        }

        public void ResolveLightMap()
        {
            EngineStuff.GraphicsDevice.SetRenderTarget(0, null);
            content = lightRT.GetTexture();
        }

        #endregion


        #region IDeferredLightMap Members

        public bool UseFloatBuffer
        {
            get
            {
                return false;
            }
        }

        #endregion

        
    }
}


